import sqlite3 as sql


DBFILE = 'User/LocalDatabase/userdata.db'  # 数据库路径
# 创建数据库连接
CONN = sql.connect(DBFILE)


def table_init():
    """
    初始化需要的表格

    :return:
        'success': 所有表格准备完毕
        not 'success': 错误信息
    """
    rslt = []  # 存储表格初始化结果
    # 每失败一个表格，将结果和错误信息存入列表 字符串 '表格名称: 错误信息\n'
    # 如果 rslt 为空，说明所有表格初始化完成

    # ---------
    # 用户操作列表
    # ---------
    create_tb_cmd = """
        CREATE TABLE IF NOT EXISTS user_operation
        (
        Oder INTEGER PRIMARY KEY,      --唯一ID,序号
        Type INT not null,      --操作类型：1 买入； 2 卖出
        Name Text not null,  --股票名称
        Code Text not null,  --股票代码
        Price Float not null,  --现价
        Date DATE not null,  --最新价日期
        BuyDate DATE not null,  --买入日期
        BuyPrice Float not null,  --买入价格
        SaleDate DATE not null,  --卖出日期
        SalePrice Float not null,  --卖出价格
        UpAndDownPrice Float not null,  --涨跌额
        UpAndDownRange Float not null  --涨跌率
        );
        """
    try:
        CONN.execute(create_tb_cmd)
        # print("user_operation 表格创建成功或连接成功！")
    except sql.OperationalError as err:
        # print(f"user_operation 表格创建失败!")
        rslt.append(f'table "user_operation" failed: {err}.\n')

    # 判断表格是否全部成功初始化
    if not rslt:
        return 'success'
    else:
        rslt_str = ''
        for s in rslt:
            rslt_str += s
        return rslt_str


def read_optionhistory(code: str):
    """
    读取个股的操作记录

    :param code:
    :return:
        【None】 - 暂无数据
        【tuple】 - 数据处理成功
            tuple[0]: 数据列
            tuple[1]: 统计结果
    """
    print(f'读取 {code} 按卖出时间倒序排序的前10条操作记录')

    cusr = CONN.cursor()  # 创建游标
    # 读取语句
    sql_cmd = f"""
SELECT BuyDate,BuyPrice,SaleDate,UpAndDownPrice,UpAndDownRange
FROM user_operation
WHERE Type=2 AND Code={code}
ORDER BY SaleDate DESC
LIMIT 15
    """
    result = cusr.execute(sql_cmd).fetchall()
    if not result:
        print('无操作记录！')
        return None
    else:
        rtrn = []

        cost_total = 0.0
        profit_total = 0.0

        # 计算两个日期函数
        def calcdate(buydate, saledate):
            from datetime import date
            # print(buydate, saledate)
            d1 = date(int(buydate[0]), int(buydate[1]), int(buydate[2]))
            d2 = date(int(saledate[0]), int(saledate[1]), int(saledate[2]))
            return (d2-d1).days

        for line in result:
            aline_list = []
            # --处理持有时间段---------
            bdate, btime = line[0].split(' ')  # 购买时间
            sdate, stime = line[2].split(' ')  # 卖出时间
            # 处理完的时间段存在一行列表
            aline_list.append(bdate + ' 至 ' + sdate)
            # --计算持有天数---------
            diff_days = calcdate(bdate.split('-'), sdate.split('-'))
            print(f"{bdate} 与 {sdate} 相差：{diff_days}天")
            # 处理完的 持有天数 存在一行列表
            aline_list.append(diff_days)
            # --处理收益------------
            aline_list.append(line[3])
            # --处理收益率------------
            aline_list.append(str(round(line[4], 2))+'%')
            # ====记录一条数据
            rtrn.append(tuple(aline_list))

            # --处理统计
            # 总成本
            cost_total += line[1]
            # 总收益
            profit_total += line[3]
        # --计算统计
        profitRange_total = profit_total / cost_total * 100  # 总收益率

        return tuple(rtrn), (round(profit_total, 2), str(round(profitRange_total, 2))+"%")


def read_localdata(t: int, col: str, sort: str):
    """
    读取持仓数据

    :param t: 1- 读取现持有; 2 - 读取历史持有
    :param col: 排序的列
    :param sort: 排序方式。'desc'降序，'asc'升序
    :return:
        【'None data'】 - 无查询结果
        【list】 -
            (
                (), # 数据列表
                (总成本, 总市值[如果为历史,则是卖出总市值], 总收益, 总收益率)  # 统计数据
            )
            ......
    """
    if t == 1:
        # 查询持有数据
        tp = 1
        col1 = 'Price'  # 最新价格字段
        col2 = 'Date'  # 最新价日期字段
    elif t == 2:
        # 历史持有
        tp = 2
        col1 = 'SalePrice'  # 卖出价格字段
        col2 = 'SaleDate'  # 卖出价日期字段
    else:
        print('read_localdata(t)传参错误！')
        return None

    sql_cmd = '''
SELECT Oder,Name,Code,BuyPrice,BuyDate,%s,%s,UpAndDownPrice,UpAndDownRange
FROM user_operation
Where Type = %s
Order By %s %s
''' % (col1, col2, tp, col, sort)
    cusr = CONN.cursor()  # 创建游标
    cusr.execute(sql_cmd)
    result = cusr.fetchall()
    cusr.close()

    if not result:
        return (), (0, 0, 0, 0)
    else:
        # 统计数据
        costPrice = 0  # 总成本
        price = 0  # 总市值
        for aline in result:
            costPrice += aline[3]
            price += aline[5]
        profit = price-costPrice  # 总收益
        myield = profit / costPrice * 100 # 总收益率
        print(f'总市值：{price}, 总成本：{costPrice}, 总收益：{profit}, 总收益率：{myield}')

        return tuple(result), (costPrice, price, profit, myield)


def read_holdlist():
    """
    读取持有，返回持有股票代码列表

    :return: tuple
    """

    sql_cmd = f'''
    SELECT Code
    FROM user_operation
    Where Type = 1
    '''
    cusr = CONN.cursor()  # 创建游标
    cusr.execute(sql_cmd)
    result = cusr.fetchall()
    cusr.close()

    rtrn_rslt = []
    for noe in result:
        rtrn_rslt.append(noe[0])

    return tuple(rtrn_rslt)


def update_hold():
    """
    更新所有持有数据

    :return:
        【'success'】 - 更新完成
        【'None data'】 - 无持有数据
        【'Time out'】 - 超时
        【'Network error'】 - 网络错误
    """
    from Internet import get_newestprice  # 导入获取最新价格函数

    # 在线程中创建的SLite对象只能在同一个线程中使用, 重新创建数据库连接
    conn = sql.connect(DBFILE)  # 链接数据库
    cusr = conn.cursor()  # 创建游标
    # 查询库中所有持有股票代码
    sql_cmd = """
SELECT Code,BuyPrice FROM user_operation WHERE Type=1
"""
    cusr.execute(sql_cmd)
    hold_list = cusr.fetchall()
    if not hold_list:
        # 无持有
        return 'None data'
    # 处理成字典
    holdDict = {}
    for hold in hold_list:
        holdDict[str(hold[0])] = hold[1]
    print(holdDict)
    # 获取最新价
    newnetDate = get_newestprice(holdDict.keys())
    if not isinstance(newnetDate, dict):
        # 返回不是字典，访问出错
        return newnetDate
    # print(f'获取的最新价：{newnetDate}')

    # 根据股票代码更新数据
    for key in newnetDate.keys():
        # 计算涨跌
        newestDate, newestPrice = newnetDate[key]  # 最新日期，最新价(返回的是字符串)
        buyPrice = holdDict[key]  # 购买价
        income = float(newestPrice) - buyPrice  # 涨跌额
        incomerate = income / buyPrice * 100  # 涨跌率
        # print(f'{key}:\n购买价：{buyPrice}\n最新价：{newestPrice}\n最新价时间：{newestDate}\n涨跌额：{income}\n涨跌率：{incomerate}')

        sql_cmd = """
UPDATE user_operation SET Price=%f, Date="%s", UpAndDownPrice=%f, UpAndDownRange=%f WHERE Code='%s' and Type=1
""" % (float(newestPrice), newestDate, income, incomerate, key)
        # print(f'SQL语句：{sql_cmd}')

        conn.execute(sql_cmd)
        conn.commit()

    return 'success'


def sale(oder, date):
    """
    模拟卖出

    :param oder: 模拟卖出的oder
    :param date: 模拟卖出的时间
    :return:
        【dict】 - 模拟卖出成功。{'Tips': 卖出提示, 'SQL': SQL执行语句}
        【'None data'】 - 库中无该条数据
        【'Not Held'】 - 已被模拟卖出
        【'TryAll error'】 - 可能库总存储的股票代码错误
        【'Time out'】 - 超时
        【'Network error'】 - 网络错误
    """
    from Internet import get_stockinfo  # 导入获取个股最新信息函数

    print(f'模拟卖出的doer:{oder}, 卖出时间：{date}')
    cusr = CONN.cursor()  # 创建游标
    sql_cmd = f"""
SELECT Type,Code,Name,BuyPrice
FROM user_operation
Where Oder = {oder}
"""
    result = cusr.execute(sql_cmd).fetchall()
    if not result:
        # 查询结果为空，可能卖出前，删除了数据库该条数据。而页面的数据缓存在内存中
        return 'None data'
    t, code, name, buyprice = result[0]  # 类型，股票代码，股票简称，购买价格
    if t != 1:
        # 不是持有状态，可能已经卖出
        return 'Not Held'
    print(f'类型: {t}, 股票代码: {code}, 股票简称: {name}, 购买价格: {buyprice}')
    # 获取最新价格
    reponse = get_stockinfo(code)
    if not isinstance(reponse, dict):
        # 如果返回不是字典，出错了
        return reponse
    newnestPrice = reponse['f2']  # 最新价格
    # 计算涨跌
    income = newnestPrice - buyprice  # 涨跌额
    incomerate = income / buyprice * 100  # 涨跌率
    # 模拟卖出确认提示语
    tips = '您正在以 %.2f 元，模拟卖出 %s(%s)，预计收益率：%.2f%%\n\n提示：\n    任何时间都可卖出，将会以最新价格预估收益！' % (
        newnestPrice, name, code, incomerate
    )
    sql_cmd = f"""
UPDATE user_operation
SET Type=2,SalePrice={newnestPrice},SaleDate="{date}",UpAndDownPrice={income},UpAndDownRange={incomerate}
WHERE Oder={oder}
"""
    return {
        'Tips': tips,
        'SQL': sql_cmd
    }


def buy(code, date):
    """
    模拟买入

    :param code: 模拟买入股票代码
    :param date: 模拟买入时间
    :return:
        【dict】 - 模拟买入成功。{'Tips': 买入提示, 'SQL': SQL执行语句}
        【Held】 - 已持有
        【'TryAll error'】 - 可能库总存储的股票代码错误
        【'Time out'】 - 超时
        【'Network error'】 - 网络错误
    """
    from Internet import get_stockinfo  # 导入获取个股最新信息函数

    print(f'模拟买入:{code}, 买入时间：{date}')
    cusr = CONN.cursor()  # 创建游标
    # 判断是否已持有
    sql_cmd = f"""
SELECT *
FROM user_operation
Where Code = {code} AND Type=1
"""
    if cusr.execute(sql_cmd).fetchall():
        # 能查询出数据，说明已经持有
        return 'Held'
    # 获取最新价格
    reponse = get_stockinfo(code)
    if not isinstance(reponse, dict):
        # 如果返回不是字典，出错了
        return reponse
    price = reponse['f2']  # 最新价格
    name = reponse['f14']  # 股票简称
    icode = reponse['f12']  # 股票代码
    tips = '您正在以 %.2f 元，模拟买入 %s(%s)。\n\n提示：\n    任何时间都可买入，将会以最新价成交！' % (
        price, name, code
    )
    sql_cmd = f"""
INSERT INTO user_operation
("Type", "Name", "Code", "Price", "Date", "BuyDate", "BuyPrice", "SaleDate", "SalePrice", "UpAndDownPrice", "UpAndDownRange")
VALUES
(1, "{name}", "{icode}", {price}, "{date}", "{date}", {price}, "1900-01-01 00:00:00", 0, 0, 0)    
"""

    return {
        'Tips': tips,
        'SQL': sql_cmd
    }


def myexecute(sql_cmd):
    """
    执行sql语句

    :param sql_cmd: SQL语句
    :return:
        【None】 - 执行成功
        【str】 - 执行失败，错误信息
    """
    cusr = CONN.cursor()  # 创建游标
    try:
        cusr.execute(sql_cmd)
        CONN.commit()
    except sql.OperationalError as error:
        # SQL语句错误
        return f'ErrorInfo: {error}\nSQL Syntax:' + sql_cmd
